#include "stm32f7xx_hal.h"

#include "device/gpio.h"
#include "driver/nt35510.h"
#include "driver/gt9147.h"

#include "i2c.h"

#include "string.h"

_gt9147_dev gt9147;
extern _nt35510_dev nt35510;

#define GT9147_PRES_DOWN 0x80  //触屏被按下
#define GT9147_CATH_PRES 0x40  //有按键按下了

#define GT9147_GPIO_PORT_RST    	GPIOA
#define GT9147_GPIO_PIN_RST    		GPIO_PIN_0

#define GT9147_GPIO_PORT_INT    	GPIOA
#define GT9147_GPIO_PIN_INT    		GPIO_PIN_3

#define GT9147_SET_PIN()	do {\
								gpio_set_pin(GT9147_GPIO_PORT_INT, GT9147_GPIO_PIN_INT, GPIO_MODE_IN, 0, 0, GPIO_PUPD_PU);\
								gpio_set_pin(GT9147_GPIO_PORT_RST, GT9147_GPIO_PIN_RST, GPIO_MODE_OUT, GPIO_OTYPE_PP, GPIO_SPEED_100M, GPIO_PUPD_PU);\
								HAL_GPIO_WritePin(GT9147_GPIO_PORT_RST, GT9147_GPIO_PIN_RST, GPIO_PIN_RESET);\
								HAL_Delay(10);\
								HAL_GPIO_WritePin(GT9147_GPIO_PORT_RST, GT9147_GPIO_PIN_RST, GPIO_PIN_SET);\
								HAL_Delay(10);\
								gpio_set_pin(GT9147_GPIO_PORT_INT, GT9147_GPIO_PIN_INT, GPIO_MODE_IN, 0, 0, GPIO_PUPD_NONE);\
								HAL_Delay(100);\
							} while(0)

#define GT9147_ADDRESS		0x28

//GT9147 部分寄存器定义
#define GT9147_CTRL_REG 	0X8040   	//GT9147控制寄存器
#define GT9147_CFGS_REG 	0X8047   	//GT9147配置起始地址寄存器
#define GT9147_CHECK_REG 	0X80FF   	//GT9147校验和寄存器
#define GT9147_PID_REG 		0X8140   	//GT9147产品ID寄存器

#define GT9147_GSTID_REG 	0X814E   	//GT9147当前检测到的触摸情况
#define GT9147_TP1_REG 		0X8150  	//第一个触摸点数据地址
#define GT9147_TP2_REG 		0X8158		//第二个触摸点数据地址
#define GT9147_TP3_REG 		0X8160		//第三个触摸点数据地址
#define GT9147_TP4_REG 		0X8168		//第四个触摸点数据地址
#define GT9147_TP5_REG 		0X8170		//第五个触摸点数据地址
//GT9147配置参数表
//第一个字节为版本号(0X60),必须保证新的版本号大于等于GT9147内部
//flash原有版本号,才会更新配置.
const uint8_t  GT9147_CFG_TBL[]=
{ 
	0X60,0XE0,0X01,0X20,0X03,0X05,0X35,0X00,0X02,0X08,
	0X1E,0X08,0X50,0X3C,0X0F,0X05,0X00,0X00,0XFF,0X67,
	0X50,0X00,0X00,0X18,0X1A,0X1E,0X14,0X89,0X28,0X0A,
	0X30,0X2E,0XBB,0X0A,0X03,0X00,0X00,0X02,0X33,0X1D,
	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X32,0X00,0X00,
	0X2A,0X1C,0X5A,0X94,0XC5,0X02,0X07,0X00,0X00,0X00,
	0XB5,0X1F,0X00,0X90,0X28,0X00,0X77,0X32,0X00,0X62,
	0X3F,0X00,0X52,0X50,0X00,0X52,0X00,0X00,0X00,0X00,
	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,
	0X0F,0X03,0X06,0X10,0X42,0XF8,0X0F,0X14,0X00,0X00,
	0X00,0X00,0X1A,0X18,0X16,0X14,0X12,0X10,0X0E,0X0C,
	0X0A,0X08,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
	0X00,0X00,0X29,0X28,0X24,0X22,0X20,0X1F,0X1E,0X1D,
	0X0E,0X0C,0X0A,0X08,0X06,0X05,0X04,0X02,0X00,0XFF,
	0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
	0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
	0XFF,0XFF,0XFF,0XFF,
};

//向GT9147写入一次数据
//reg:起始寄存器地址
//buf:数据缓缓存区
//len:写数据长度
//返回值:0,成功;1,失败.
uint8_t gt9147_write_reg(uint16_t reg, uint8_t *buf, uint8_t len)
{
	HAL_I2C_Mem_Write(&hi2c1, (uint16_t)GT9147_ADDRESS, (uint16_t)reg, I2C_MEMADD_SIZE_16BIT, (uint8_t *)buf, len, 0xff);

    return 0;
}
//从GT9147读出一次数据
//reg:起始寄存器地址
//buf:数据缓缓存区
//len:读数据长度			  
void gt9147_read_reg(uint16_t  reg,uint8_t  *buf,uint8_t  len)
{
	HAL_I2C_Mem_Read(&hi2c1, (uint16_t)GT9147_ADDRESS, (uint16_t)reg, I2C_MEMADD_SIZE_16BIT, (uint8_t *)buf, len, 0xff);
} 

//发送GT9147配置参数
//mode:0,参数不保存到flash
//     1,参数保存到flash
uint8_t  gt9147_send_cfg(uint8_t  mode)
{
	uint8_t  buf[2];
	uint8_t  i=0;
	buf[0]=0;
	buf[1]=mode;	//是否写入到GT9147 FLASH?  即是否掉电保存
	for(i=0;i<sizeof(GT9147_CFG_TBL);i++)buf[0]+=GT9147_CFG_TBL[i];//计算校验和
    buf[0]=(~buf[0])+1;
	gt9147_write_reg(GT9147_CFGS_REG,(uint8_t *)GT9147_CFG_TBL,sizeof(GT9147_CFG_TBL));//发送寄存器配置
	gt9147_write_reg(GT9147_CHECK_REG,buf,2);//写入校验和,和配置更新标记
	return 0;
}

//初始化GT9147触摸屏
//返回值:0,初始化成功;1,初始化失败 
uint8_t  gt9147_init(void)
{
	uint8_t  temp[5];

	GT9147_SET_PIN();

	gt9147_read_reg(GT9147_PID_REG,temp,4);//读取产品ID
	temp[4]=0;
	printf("CTP ID:%s\r\n",temp);	//打印ID
	if (strcmp((char*)temp,"9147")==0) {//ID==9147
		temp[0]=0X02;			
		gt9147_write_reg(GT9147_CTRL_REG,temp,1);//软复位GT9147
		gt9147_read_reg(GT9147_CFGS_REG,temp,1);//读取GT9147_CFGS_REG寄存器
		if(temp[0]<0X60) {//默认版本比较低,需要更新flash配置
			printf("Default Ver:%d\r\n",temp[0]);
			gt9147_send_cfg(1);//仅4.3寸MCU屏,更新并保存配置
		}
		temp[0]=0X00;	 
		gt9147_write_reg(GT9147_CTRL_REG,temp,1);//结束复位
		return 0;
	}
	gt9147.touchtype |= nt35510.dir & 0x01;
	return 1;
}
const uint16_t  GT9147_TPX_TBL[5]={GT9147_TP1_REG,GT9147_TP2_REG,GT9147_TP3_REG,GT9147_TP4_REG,GT9147_TP5_REG};
//扫描触摸屏(采用查询方式)
//mode:0,正常扫描.
//返回值:当前触屏状态.
//0,触屏无触摸;1,触屏有触摸
uint8_t  gt9147_scan(uint8_t  mode)
{
	uint8_t  buf[4];
	uint8_t  i=0;
	uint8_t  res=0;
	uint8_t  temp;
	uint8_t  tempsta;
 	static uint8_t  t=0;//控制查询间隔,从而降低CPU占用率
	t++;
	if((t%10)==0||t<10)//空闲时,每进入10次CTP_Scan函数才检测1次,从而节省CPU使用率
	{
		gt9147_read_reg(GT9147_GSTID_REG,&mode,1);	//读取触摸点的状态
 		if((mode&0x80)&&((mode&0xF)<6))
		{
			temp=0;
			gt9147_write_reg(GT9147_GSTID_REG,&temp,1);//清标志
		}		
		if((mode&0xF)&&((mode&0xF)<6))
		{
			temp=0XFF<<(mode&0XF);		//将点的个数转换为1的位数,匹配gt9147.sta定义
			tempsta=gt9147.sta;			//保存当前的gt9147.sta值
			gt9147.sta=(~temp)|GT9147_PRES_DOWN|GT9147_CATH_PRES;
			gt9147.x[4]=gt9147.x[0];	//保存触点0的数据
			gt9147.y[4]=gt9147.y[0];
			for(i=0;i<5;i++)
			{
				if(gt9147.sta&(1<<i))	//触摸有效?
				{
					gt9147_read_reg(GT9147_TPX_TBL[i],buf,4);	//读取XY坐标值
                        if(gt9147.touchtype&0X01)//横屏
                        {
                            gt9147.y[i]=((uint16_t )buf[1]<<8)+buf[0];
                            gt9147.x[i]=800-(((uint16_t )buf[3]<<8)+buf[2]);
                        }else
                        {
                            gt9147.x[i]=((uint16_t )buf[1]<<8)+buf[0];
                            gt9147.y[i]=((uint16_t )buf[3]<<8)+buf[2];
                        }
					//printf("x[%d]:%d,y[%d]:%d\r\n",i,gt9147.x[i],i,gt9147.y[i]);
				}			
			} 
			res=1;
			if(gt9147.x[0]>nt35510.width||gt9147.y[0]>nt35510.height)//非法数据(坐标超出了)
			{ 
				if((mode&0XF)>1)		//有其他点有数据,则复第二个触点的数据到第一个触点.
				{
					gt9147.x[0]=gt9147.x[1];
					gt9147.y[0]=gt9147.y[1];
					t=0;				//触发一次,则会最少连续监测10次,从而提高命中率
				}else					//非法数据,则忽略此次数据(还原原来的)  
				{
					gt9147.x[0]=gt9147.x[4];
					gt9147.y[0]=gt9147.y[4];
					mode=0X80;		
					gt9147.sta=tempsta;	//恢复gt9147.sta
				}
			}else t=0;					//触发一次,则会最少连续监测10次,从而提高命中率
		}
	}
	if((mode&0X8F)==0X80)//无触摸点按下
	{ 
		if(gt9147.sta&GT9147_PRES_DOWN)	//之前是被按下的
		{
			gt9147.sta&=~(1<<7);	//标记按键松开
		}else						//之前就没有被按下
		{ 
			gt9147.x[0]=0xffff;
			gt9147.y[0]=0xffff;
			gt9147.sta&=0XE0;	//清除点有效标记
		}	 
	} 	
	if(t>240)t=10;//重新从10开始计数
	return res;
}
